﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SynapseGaming.LightingSystem.Core;
using SynapseGaming.LightingSystem.Rendering;
using SynapseGaming.LightingSystem.Lights;
using Microsoft.Xna.Framework;
using System.Diagnostics;

namespace The_LarX
{
    public class Renderer_SunBurn : Renderer
    {
        public static bool CreatedSplashScreen;

        // The SunBurn lighting system.
        public LightingSystemManager LightingSystemManager;
        public FrameBuffers FrameBuffers;

        // Scene related members.
        public SceneState SceneState;
        public SceneInterface SceneInterface;
        public SceneEnvironment Environment;

        public bool RenderingToScreen = true;

        public Renderer_SunBurn(bool MakeFrameBuffer)
        {
            Load(MakeFrameBuffer);
        }
        public Renderer_SunBurn()
        {
            Load(true);
        }
        public Renderer_SunBurn(GameScreen screen)
            : base(screen)
        {
            Load(true);
        }
        public Renderer_SunBurn(Camera3D Camera, GameScreen screen)
            : base(screen)
        {
            Load(true);
            this.Camera = Camera;
        }

        public override float GetDistance(Vector3 position)
        {
            if (Camera != null)
            {
                return Vector3.Distance(Camera.Position, position);
            }
            else
            {
                return 0;
            }
        }

        private void Load(bool make)
        {
            if (!SplashScreenGameComponent.DisplayComplete && !CreatedSplashScreen)
            {
                SplashScreenGameComponent splashScreenGameComponent = new SplashScreenGameComponent(Engine.Game, Engine.IGraphicsDeviceService);
                Engine.Game.Components.Add(splashScreenGameComponent);
                CreatedSplashScreen = true;
            }

            LightingSystemManager = new LightingSystemManager(Engine.Services, Engine.Content);
            SceneState = new SceneState();

            SceneInterface = new SceneInterface(Engine.IGraphicsDeviceService);
            SceneInterface.CreateDefaultManagers(false);

            //SceneInterface.AddManager(new DebugRenderManager(Engine.IGraphicsDeviceService, SceneInterface));

            if (make)
            {
                FrameBuffers = new FrameBuffers(Engine.IGraphicsDeviceService, DetailPreference.High, DetailPreference.Medium);
                SceneInterface.ResourceManager.AssignOwnership(FrameBuffers);
            }

            Environment = new SceneEnvironment();
            Environment.VisibleDistance = 500;
            Environment.FogEnabled = true;
            Environment.FogStartDistance = 450;
            Environment.FogEndDistance = 500;
            Environment.ShadowFadeStartDistance = 400;
            Environment.ShadowFadeEndDistance = 450;
            Environment.ShadowCasterDistance = 450;

            SceneInterface.ShowStatistics = true;
            SceneInterface.StatisticCategories = SystemStatisticCategory.Performance;

            /*LightingSystemPreferences preferences = new LightingSystemPreferences();
            preferences.EffectDetail = DetailPreference.Off;
            preferences.LightingDetail = DetailPreference.Off;
            preferences.PostProcessingDetail = DetailPreference.Off;
            preferences.ShadowDetail = DetailPreference.Off;
            SceneInterface.ApplyPreferences(preferences);*/
        }  

            public void Disable()
            {
                SceneInterface.Clear();
                SceneInterface.Unload();
            }

            public override void RemoveActor(Actor actor)
            {
                SceneInterface.ObjectManager.Remove(actor.SceneObject);
            }

            public override void SubmitActor(Actor actor)
            {
                if (actor.Visible || Engine.Editor)
                    SceneInterface.ObjectManager.Submit(actor.SceneObject);
            }
            public override void SubmitLight(object Light)
            {
                if (Light is BaseLight)
                {
                    BaseLight light = Light as BaseLight;
                    SceneInterface.LightManager.Submit(light);
                }
            }

            public override void Update()
            {
                SceneInterface.Update(Engine.GameTime);
            }

            public override void Draw()
            {
                base.Draw();
            }

            public override void RenderActors()
            {
                long StartTime = Stopwatch.GetTimestamp();
                if (Camera != null)
                {
                    Camera.FarPlane = Environment.VisibleDistance;
                    if (!SplashScreenGameComponent.DisplayComplete)
                        return;
                    // Render the scene
                    SceneState.BeginFrameRendering(Camera.View, Camera.Projection, Engine.GameTime, Environment, FrameBuffers, RenderingToScreen);
                    SceneInterface.BeginFrameRendering(SceneState);
                
                    // Add custom rendering that should occur before the scene is rendered.
                    if (BeforeTheSceneIsRendered != null)
                        BeforeTheSceneIsRendered();

                    SceneInterface.RenderManager.Render();

                    if (AfterTheSceneIsRendered != null)
                        AfterTheSceneIsRendered();

                    // Add custom rendering that should occur after the scene is rendered.
                    SceneInterface.EndFrameRendering();
                    SceneState.EndFrameRendering();
                }

                if (Engine.DebugMode)
                {
                    long endDrawTime = Stopwatch.GetTimestamp();
                    double accumulatedPhysicsTime = (endDrawTime - StartTime) / (double)Stopwatch.Frequency;
                    int DrawTime = (int)(accumulatedPhysicsTime * 1000);
                    Engine.RenderManager.DrawString("SunBurn Time:" + DrawTime, 2, 200, new Vector2(50, 200),
                        "Kootenay", Color.White, null);
                }
            }

            public override void SerializeData()
            {
                base.SerializeData();

                Data.AddData("Environment.BloomAmount", Environment.BloomAmount);
                Data.AddData("Environment.BloomThreshold", Environment.BloomThreshold);
                Data.AddData("Environment.DynamicRangeCinematicAmount", Environment.DynamicRangeCinematicAmount);
                Data.AddData("Environment.DynamicRangeDarkenAmount", Environment.DynamicRangeDarkenAmount);
                Data.AddData("Environment.DynamicRangeEnabled", Environment.DynamicRangeEnabled);
                Data.AddData("Environment.DynamicRangeSaturationAmount", Environment.DynamicRangeSaturationAmount);
                Data.AddData("Environment.DynamicRangeTransitionMaxScale", Environment.DynamicRangeTransitionMaxScale);
                Data.AddData("Environment.DynamicRangeTransitionMinScale", Environment.DynamicRangeTransitionMinScale);
                Data.AddData("Environment.DynamicRangeTransitionTime", Environment.DynamicRangeTransitionTime);
                Data.AddData("Environment.ExposureAmount", Environment.ExposureAmount);
                Data.AddData("Environment.FogColor", Environment.FogColor);
                Data.AddData("Environment.FogEnabled", Environment.FogEnabled);
                Data.AddData("Environment.FogEndDistance", Environment.FogEndDistance);
                Data.AddData("Environment.FogStartDistance", Environment.FogStartDistance);
                Data.AddData("Environment.ShadowCasterDistance", Environment.ShadowCasterDistance);
                Data.AddData("Environment.ShadowFadeEndDistance", Environment.ShadowFadeEndDistance);
                Data.AddData("Environment.ShadowFadeStartDistance", Environment.ShadowFadeStartDistance);
                Data.AddData("Environment.VisibleDistance", Environment.VisibleDistance);
            }

            public override void DeserializeData()
            {
                base.DeserializeData();

                Environment.BloomAmount = Data.GetData<float>("Environment.BloomAmount");
                Environment.BloomThreshold = Data.GetData<float>("Environment.BloomThreshold");
                Environment.DynamicRangeCinematicAmount = Data.GetData<float>("Environment.DynamicRangeCinematicAmount");
                Environment.DynamicRangeDarkenAmount = Data.GetData<float>("Environment.DynamicRangeDarkenAmount");
                Environment.DynamicRangeEnabled = Data.GetData<bool>("Environment.DynamicRangeEnabled");
                Environment.DynamicRangeSaturationAmount = Data.GetData<float>("Environment.DynamicRangeSaturationAmount");
                Environment.DynamicRangeTransitionMaxScale = Data.GetData<float>("Environment.DynamicRangeTransitionMaxScale");
                Environment.DynamicRangeTransitionMinScale = Data.GetData<float>("Environment.DynamicRangeTransitionMinScale");
                Environment.DynamicRangeTransitionTime = Data.GetData<float>("Environment.DynamicRangeTransitionTime");
                Environment.ExposureAmount = Data.GetData<float>("Environment.ExposureAmount");
                Environment.FogColor = Data.GetData<Vector3>("Environment.FogColor");
                Environment.FogEnabled = Data.GetData<bool>("Environment.FogEnabled");
                Environment.FogEndDistance = Data.GetData<float>("Environment.FogEndDistance");
                Environment.FogStartDistance = Data.GetData<float>("Environment.FogStartDistance");
                Environment.ShadowCasterDistance = Data.GetData<float>("Environment.ShadowCasterDistance");
                Environment.ShadowFadeEndDistance = Data.GetData<float>("Environment.ShadowFadeEndDistance");
                Environment.ShadowFadeStartDistance = Data.GetData<float>("Environment.ShadowFadeStartDistance");
                Environment.VisibleDistance = Data.GetData<float>("Environment.VisibleDistance");
            }
        }
}
